﻿using Moda.Libraries.StringExtension.Korean;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;

namespace StringChosungExtensionTestProject
{


    /// <summary>
    ///This is a test class for StringChosungExtensionTest and is intended
    ///to contain all StringChosungExtensionTest Unit Tests
    ///</summary>
    [TestClass()]
    public class KoreanStringExtensionTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for Jamo Match
        ///</summary>
        [TestMethod()]
        public void JamoMatchesTest()
        {
            string str = "오빤 강남스타일";
            string[] keyword = { "가ㄴ스타", "압구정 스타일", "오빤 강나암ㅅㅌㅇ", "" };
            bool[] expected = { true, false, false, true };
            bool actual;

            for (int i = 0; i < keyword.Length; i++)
            {
                actual = str.KContains(keyword[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }

        /// <summary>
        ///A test for JamoEquals
        ///</summary>
        [TestMethod()]
        public void JamoMatchesTest_SameChar()
        {
            char[] c = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            char[] keyword1 = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            char[] keyword2 = { 'ㄴ', '나', '고', 'ㄷ', 'ㅁ', 'ㅠ', 'B', ' ' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;
            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension.KEquals(c[i], keyword1[i]);
                actual2 = KoreanStringExtension.KEquals(c[i], keyword2[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }

        /// <summary>
        ///A test for JamoEquals
        ///</summary>
        [TestMethod()]
        public void JamoMatchesTest_Level1Char()
        {
            char[] c = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            char[] keywords_true = { 'ㄱ', 'ㄱ', 'ㄱ', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            char[] keywords_false = { 'ㄴ', 'ㄴ', 'ㄴ', 'ㄷ', 'ㅁ', 'ㅠ', 'B', ' ' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;
            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension.KEquals(c[i], keywords_true[i]);
                actual2 = KoreanStringExtension.KEquals(c[i], keywords_false[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }

        /// <summary>
        ///A test for JamoEquals
        ///</summary>
        [TestMethod()]
        public void JamoMatchesTest_Level2Char()
        {
            char[] c = { '가', '각', '남', '훗', '양' };
            char[] keywords_true = { '가', '가', '나', '후', '야' };
            char[] keywords_false = { '고', '나', '놔', '푸', '여' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;
            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension.KEquals(c[i], keywords_true[i]);
                actual2 = KoreanStringExtension.KEquals(c[i], keywords_false[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }

        /// <summary>
        ///A test for JamoEquals
        ///</summary>
        [TestMethod()]
        public void JamoMatchesTest_Level3Char()
        {
            char[] c = { '각', '남', '훗', '양' };
            char[] keyword1 = { '각', '남', '훗', '양' };
            char[] keyword2 = { '고', '너', '놔', '푸' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;
            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension.KEquals(c[i], keyword1[i]);
                actual2 = KoreanStringExtension.KEquals(c[i], keyword2[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }


        /// <summary>
        ///A test for IsInHangulSyllablesRange
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void IsInHangulSyllablesRangeTest()
        {
            char[] c = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            bool[] expected = { false, true, true, false, false, false, false, false };
            bool actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.IsInHangulSyllablesRange(c[i]);
                Assert.AreEqual(expected[i], actual);
            }

        }

        /// <summary>
        ///A test for IsInJamoRange
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void IsInJamoRangeTest()
        {
            char[] c = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            bool[] expected = { true, false, false, true, true, false, false, false };
            bool actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.IsInJamoRange(c[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }

        /// <summary>
        ///A test for IsLevel1Char
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void IsLevel1CharTest()
        {
            char[] c = { 'ㄱ', '가', '곽', 'ㄴ', 'ㅗ', 'A', '2', '*' };
            bool[] expected = { true, false, false, true, false, false, false, false };
            bool actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.IsLevel1Char(c[i]);
                Assert.AreEqual(expected[i], actual);
            }

        }

        /// <summary>
        ///A test for FindJamoLevel
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void FindJamoLevelTest()
        {
            char[] c = { 'ㄱ', '가', '각', '나', '뙇', 'a', '#', '@', 'ㅎ' };
            int[] expected = { 1, 2, 3, 2, 3, 0, 0, 0, 1 };
            int actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.FindJamoLevel(c[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }

        /// <summary>
        ///A test for LetterToChosung
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void LetterToChosungTest()
        {
            char[] c = { '\x3131', '\x3132', '\x3133' };
            char[] expected = { '\x1100', '\x1101', '\x3133' };
            char actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.LetterToChosung(c[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }



        /// <summary>
        ///A test for Level1Normalizer
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void Level1NormalizerTest()
        {
            char[] c = { 'ㄱ', 'ㄴ', '가', '각', '뙇', '확' };
            char[] expected = { 'ㄱ', 'ㄴ', 'ㄱ', 'ㄱ', 'ㄸ', 'ㅎ' };
            char actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.Level1Normalizer(c[i]);

                actual = KoreanStringExtension_Accessor.LetterToChosung(actual);
                expected[i] = KoreanStringExtension_Accessor.LetterToChosung(expected[i]);

                Assert.AreEqual(expected[i], actual);
            }

        }

        /// <summary>
        ///A test for Level2Normalizer
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void Level2NormalizerTest()
        {
            char[] c = { '과', '난', '가', '각', '뙇', '확' };
            char[] expected = { '과', '나', '가', '가', '똬', '화' };
            char actual;

            for (int i = 0; i < c.Length; i++)
            {
                actual = KoreanStringExtension_Accessor.Level2Normalizer(c[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }


        /// <summary>
        ///A test for Level1JamoMatch
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void Level1JamoMatchTest()
        {
            char[] c = { '가', '각', '과', '놔', '다', '뙇', '하', '함', '하', '망', '과', '제', '궯' };
            char[] keyword1 = { 'ㄱ', 'ㄱ', 'ㄱ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㅎ', 'ㅎ', 'ㅎ', 'ㅁ', 'ㄱ', 'ㅈ', 'ㄱ' };
            char[] keyword2 = { 'ㅍ', 'ㅍ', 'ㅍ', 'ㅍ', 'ㅍ', 'ㅍ', 'ㅋ', 'ㅋ', 'ㅋ', 'ㅋ', 'ㅋ', 'ㅂ', 'ㄴ' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;

            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension_Accessor.Level1JamoMatch(c[i], keyword1[i]);
                actual2 = KoreanStringExtension_Accessor.Level1JamoMatch(c[i], keyword2[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }

        /// <summary>
        ///A test for Level2JamoMatch
        ///</summary>
        [TestMethod()]
        [DeploymentItem("ChosungStringExtension.dll")]
        public void Level2JamoMatchTest()
        {
            char[] c = { '가', '각', '과', '놔', '다', '뙇', '하', '함', '하', '망', '과', '제', '궯' };
            char[] keyword1 = { '가', '가', '과', '놔', '다', '똬', '하', '하', '하', '마', '과', '제', '궤' };
            char[] keyword2 = { '과', '거', '나', '화', '카', '카', '카', '카', '카', '카', '카', '카', '카' };
            bool expected1 = true;
            bool expected2 = false;
            bool actual1, actual2;

            for (int i = 0; i < c.Length; i++)
            {
                actual1 = KoreanStringExtension_Accessor.Level2JamoMatch(c[i], keyword1[i]);
                actual2 = KoreanStringExtension_Accessor.Level2JamoMatch(c[i], keyword2[i]);
                Assert.AreEqual(expected1, actual1);
                Assert.AreEqual(expected2, actual2);
            }
        }

        /// <summary>
        ///A test for JamoIndexOf
        ///</summary>
        [TestMethod()]
        public void KIndexOfTest()
        {
            string[] s = { "강남스타일", "Gangnam Style", "동해물과", "백두산이", "A학점", "!@#$" };
            string[] keyword = { "ㄱ남ㅅㅌ이", "nam", "해ㅁ", "ㅁㄴㅇㄹ", "A학", "#" };
            int[] expected = { 0, 4, 1, -1, 0, 2 };

            int actual;
            for (int i = 0; i < s.Length; i++)
            {
                actual = s[i].KIndexOf(keyword[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }



        /// <summary>
        ///A test for KMatches
        ///</summary>
        [TestMethod()]
        public void KMatchesTest()
        {
            string str = "동해물과 백두산이";
            string[] keywords = {"ㄷㅎㅁㄱ", "백두산이", "ㅁㄴㅇㄹ", ""};
            string[] expectedResults = {"동해물과", "백두산이", null, ""};
            string actual;

            for (int i = 0; i < keywords.Length; i++)
            {
                actual = str.KMatches(keywords[i]);
                Assert.AreEqual(expectedResults[i], actual);
            }
            
        }

        /// <summary>
        ///A test for KEquals
        ///</summary>
        [TestMethod()]
        public void KEqualsTest()
        {
            string str_hangulOnly = "마르고 닳도록";
            string str_complex = "Korean한글1";
            
            string[] keywordsForHangulOnly = { "ㅁㄹㄱ ㄷㄷㄹ", "마르고 닳도록", "ㅁㄹㄱ", "ㄷㄷㄹ" };
            string[] keywordsForComplex = { "Koreanㅎㄱ1", "Korean한글1", "ㅎㄱ", "Korean" };

            bool[] expectedResultsForHangulOnly = { true, true, false, false };
            bool[] expectedResultsForComplex = { true, true, false, false };

            bool actual;

            for (int i = 0; i < keywordsForHangulOnly.Length; i++)
            {
                actual = str_hangulOnly.KEquals(keywordsForHangulOnly[i]);
                Assert.AreEqual(expectedResultsForHangulOnly[i], actual);
            }

            for (int i = 0; i < keywordsForComplex.Length; i++)
            {
                actual = str_complex.KEquals(keywordsForComplex[i]);
                Assert.AreEqual(expectedResultsForComplex[i], actual);
            }
        }


        /// <summary>
        ///A test for KMatches
        ///</summary>
        [TestMethod()]
        public void KMatches_WithLambdaTest()
        {
            string str = "하느님이 보우하사";
            string keyword = "ㅎㄴㄴㅁ";
            string expected = "우리나라만세";
            string actual;

            actual = str.KMatches(keyword, (s, k) => { return "우리나라만세"; });
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for KMatches
        ///</summary>
        [TestMethod()]
        public void KMatches_WithInterfaceTest()
        {
            string str = "하느님이 보우하사";
            string keyword = "ㅎㄴㄴㅁ";
            string expected_string = TestComparator.FIXED_RETURN_VALUE_STRING;
            int expected_int = TestComparator.FIXED_RETURN_VALUE_INT;
            bool expected_bool = TestComparator.FIXED_RETURN_VALUE_BOOL;
            string actual_string;
            int actual_int;
            bool actual_bool;

            TestComparator kComparator = new TestComparator();

            actual_string = str.KMatches(keyword, kComparator);
            actual_int = str.KIndexOf(keyword, kComparator);
            actual_bool = str.KEquals(keyword, kComparator);

            Assert.AreEqual(expected_string, actual_string);
            Assert.AreEqual(expected_int, actual_int);
            Assert.AreEqual(expected_bool, actual_bool);
        }

        private class TestComparator : KoreanStringExtension.IStringSpecialComparator
        {
            internal const int FIXED_RETURN_VALUE_INT = 12345;
            internal const string FIXED_RETURN_VALUE_STRING = "무궁화 삼천리";
            internal const bool FIXED_RETURN_VALUE_BOOL = false;

            public string Matches(string s, string keyword)
            {
                return FIXED_RETURN_VALUE_STRING;
            }

            public int IndexOf(string s, string keyword)
            {
                return FIXED_RETURN_VALUE_INT;
            }

            public bool Equals(char s, char keyword)
            {
                return FIXED_RETURN_VALUE_BOOL;
            }
        }

        /// <summary>
        ///A test for appendJosa
        ///</summary>
        [TestMethod()]
        public void KAppendJosaTest()
        {
            string[] strs = { "한글", "조사", "Hangul" };
            string[] expected = { "한글이", "조사가", "Hangul" };
            string actual;

            for (int i = 0; i < strs.Length; i++)
            {
                actual = strs[i].KAppendJosa("이", "가");
                Assert.AreEqual(expected[i], actual);
            }
        }

        public void KAppendJosaTest2()
        {
            string[] strs = { "한글", "조사", "Hangul", "동해물", "백두산", "무궁화" };
            JosaType[] josaTypes = { JosaType.EN, JosaType.ER, JosaType.ER, JosaType.WG, JosaType.YG, JosaType.YDD };
            string[] expected = { "한글은", "조사를", "Hangul", "동해물과", "백두산이", "무궁화다" };
            string actual;

            for (int i = 0; i < strs.Length; i++)
            {
                actual = strs[i].KAppendJosa(josaTypes[i]);
                Assert.AreEqual(expected[i], actual);
            }
        }

        /// <summary>
        ///A test for KExtractChosung
        ///</summary>
        [TestMethod()]
        public void KExtractChosungTest()
        {
            string[] strs = { "동해물과", "백두Mountain이", "ㅁㄴㅇㄹ", "ㅏㅑㅓㅕ" };
            string[] expecteds = { "ㄷㅎㅁㄱ", "ㅂㄷMountainㅇ", "ㅁㄴㅇㄹ", "ㅏㅑㅓㅕ" };
            string actual;

            for (int i = 0; i < strs.Length; i++)
            {
                actual = strs[i].KExtractChosung();
                Assert.AreEqual(expecteds[i], actual);
            }
        }
    }
}
